#pragma once
#include <etcd/Client.hpp>
#include <etcd/KeepAlive.hpp>
#include <etcd/Response.hpp>
#include <etcd/Watcher.hpp>
#include <etcd/Value.hpp>
#include <functional>
#include "logger.hpp"

namespace mag {
    // 服务注册客户端类
    class Registry 
    {
    public:
        using ptr = std::shared_ptr<Registry>;

        // 构造函数：初始化etcd客户端和租约（Lease）机制
        Registry(const std::string &host):
            _client(std::make_shared<etcd::Client>(host)), // 创建etcd客户端
            _keep_alive(_client->leasekeepalive(3).get()), // 创建一个3秒TTL的租约并保持续约
            _lease_id(_keep_alive->Lease()){} // 获取租约ID

        // 析构函数：取消租约续约，释放资源
        ~Registry() { _keep_alive->Cancel(); }

        // 注册服务信息：将键值对存入etcd并绑定租约
        bool registry(const std::string &key, const std::string &val) 
        {
            auto resp = _client->put(key, val, _lease_id).get(); // 绑定租约，写入键值对
            if (resp.is_ok() == false) 
            {
                LOG_ERROR("注册数据失败：{}", resp.error_message()); // 打印错误日志
                return false;
            }
            return true; // 返回注册结果
        }
    private:
        std::shared_ptr<etcd::Client> _client; // etcd客户端对象
        std::shared_ptr<etcd::KeepAlive> _keep_alive; // 租约续约对象
        uint64_t _lease_id; // 租约ID
    };

    // 服务发现客户端类
    class Discovery 
    {
    public:
        using ptr = std::shared_ptr<Discovery>;
        using NotifyCallback = std::function<void(std::string, std::string)>;

        // 构造函数：初始化etcd客户端，执行服务发现和事件监听
        Discovery(const std::string &host, 
            const std::string &basedir,
            const NotifyCallback &put_cb,
            const NotifyCallback &del_cb)
            :_client(std::make_shared<etcd::Client>(host)), // 创建etcd客户端
             _put_cb(put_cb), _del_cb(del_cb) // 设置回调函数
            {
            // 服务发现：获取当前路径下的已有服务数据
            auto resp = _client->ls(basedir).get(); // 列出路径下的所有键值
            if (resp.is_ok() == false) 
            {
                LOG_ERROR("获取服务信息数据失败：{}", resp.error_message()); // 打印错误日志
            }
            int sz = resp.keys().size();
            for (int i = 0; i < sz; ++i) 
            {
                if (_put_cb) _put_cb(resp.key(i), resp.value(i).as_string()); // 调用服务新增回调
            }

            // 事件监控：监听路径数据变更并调用回调处理
            _watcher = std::make_shared<etcd::Watcher>(*_client.get(), basedir,
                std::bind(&Discovery::callback, this, std::placeholders::_1), true);
        }

        // 析构函数：取消事件监听，释放资源
        ~Discovery() {
            _watcher->Cancel();
        }
    private:
        // 事件回调函数：处理服务新增和删除事件
        void callback(const etcd::Response &resp) 
        {
            if (resp.is_ok() == false) {
                LOG_ERROR("收到一个错误的事件通知: {}", resp.error_message()); // 打印错误日志
                return;
            }
            for (auto const& ev : resp.events()) 
            {
                // 新增服务事件
                if (ev.event_type() == etcd::Event::EventType::PUT) {
                    if (_put_cb) _put_cb(ev.kv().key(), ev.kv().as_string()); // 调用服务新增回调
                    LOG_DEBUG("新增服务：{}-{}", ev.kv().key(), ev.kv().as_string()); // 打印调试信息
                }
                // 服务下线事件
                else if (ev.event_type() == etcd::Event::EventType::DELETE_) {
                    if (_del_cb) _del_cb(ev.prev_kv().key(), ev.prev_kv().as_string()); // 调用服务删除回调
                    LOG_DEBUG("下线服务：{}-{}", ev.prev_kv().key(), ev.prev_kv().as_string()); // 打印调试信息
                }
            }
        }
    private:
        NotifyCallback _put_cb; // 服务新增事件回调
        NotifyCallback _del_cb; // 服务删除事件回调
        std::shared_ptr<etcd::Client> _client; // etcd客户端对象
        std::shared_ptr<etcd::Watcher> _watcher; // 事件监听器
    };
}
